#pragma once
#include "Socket.hpp"
#include <iostream>
#include <string>
#include <memory>
#include <jsoncpp/json/json.h>
#include <functional>

using namespace SocketModule;

// client -> server
// 如何要做序列化和反序列化：
// 1. 我们自己写(怎么做) ---> 往往不具备很好的扩展性
// 2. 使用现成的方案(这个是我们要写的) ---> json -> jsoncpp
class Request
{
public:
    Request(){}
    Request(int x,int y,char oper)
        :_x(x)
        ,_y(y)
        ,_oper(oper)
    {}
    ~Request(){}
    std::string Serialize()
    {
        Json::Value root;

        // 用空格作为分隔符。
        // 
        root["x"] = _x;
        root["y"] = _y;
        root["oper"] = _oper;

        Json::FastWriter writer;
        std::string s = writer.write(root);

        return s;
    }
    bool Deserialize(std::string& in)
    {
        // "10" "20" '+' -> 以空格作为分隔符-> 10 20 '+'
        Json::Value root;
        Json::Reader reader;
        bool ok = reader.parse(in,root);
        if(ok)
        {
            _x = root["x"].asInt();
            _y = root["y"].asInt();
            _oper = root["oper"].asInt();

            return true;
        }

        return false;
    }
    int X()
    {
        return _x;
    }
    int Y()
    {
        return _y;
    }
    char Oper()
    {
	    return _oper;
    }
private:
    int _x;
    int _y;
    char _oper;
};

class Response
{
public:
    Response()
    {}
    Response(int result,int code)
        :_result(result)
        ,_code(code)
    {}
    ~Response()
    {}
    // 序列化 
    std::string Serialize()
    {
        Json::Value root;

        root["result"] = _result;
        root["code"] = _code;

        Json::FastWriter writer;

        return writer.write(root);
    }
    // 反序列化
    bool Deserialize(std::string& in)
    {
        Json::Value root;

        Json::Reader reader;

        bool ok = reader.parse(in,root);

        if(ok)
        {
            _result = root.asInt();
            _code = root.asInt();
        }

        return ok;
    }
    // 设置外部调用接口，方便修改值。
    void SetResult(int res)
    {
        _result = res;
    }
    void SetCode(int code)
    {
        _code = code;
    }
    void ShowResult()
    {
        std::cout << "计算结果是:" << _result << "[" << _code << "]" << std::endl;
    }
private:
    int _result;
    int _code;
};

const std::string sep = "\r\n";

using func_t = std::function<Response(Request& req)>;

// 协议(基于TCP的)需要解决两个问题：
// 1. request和response必须得有序列化和反序列化功能
// 2. 你必须保证，读取的时候，读到完整的请求(UDP不用考虑)
class Protocol
{
public:
    Protocol()
    {}
    Protocol(func_t func)
        :_func(func)
    {}
    std::string Encode (const std::string& jsonster)
    {
        // 引用层封装报头。
        std::string len = std::to_string(jsonster.size());
        return len + sep + jsonster + sep;
    }
    // 1. 判断报文完整性
    // 2. 如果包含至少一个完整请求，提取他， 并从移除它，方便处理下一个
    // 参数一为报文，参数二为输出型参数(好拿一些，毕竟可以+=其他字符串)。
    bool Decode(std::string& buffer,std::string* package)
    {
        ssize_t pos = buffer.find(sep);
        // 没找到sep，说明报头不完整。
        if(pos == std::string::npos)
        {
            return false;
        }
        // 因为删除是一个完整请求一个完整请求的删除，所以我们默认下表0是某个报文的报头。
        // 也就是字节数(内存)。
        std::string package_len_str = buffer.substr(0,pos);
        int package_len_int = std::stoi(package_len_str);

        // 数字转字符串长度 + 两个分隔符长度 + 报文本身长度 = 总长度
        int target_len = package_len_str.size() + package_len_int + 2 * sep.size();
        // 报文有分隔符也可能没读完整。
        if(target_len > buffer.size())
        {
            return false;
        }
        // 跳过报文长度和一个分隔符，直接读取出报文的大小。
        *package = buffer.substr(pos + sep.size(),package_len_int);
        // 已经提取出了。
        // 也就没必要保留了。
        buffer.erase(0,target_len);

        return true;
    }
    // 获取请求。
    void GetRequest(std::shared_ptr<Socket>& sock,InetAddr& client)
    {
        // 读取
        std::string buffer_queue;
        while(true)
        {
            int n = sock->Recv(&buffer_queue);
            // 1. 解析报文，提取完整的json请求，如果不完整，就让服务器继续读取
            if(n > 0)
            {
                std::cout << "-----------request_buffer--------------" << std::endl;
                std::cout << buffer_queue << std::endl;
                std::cout << "------------------------------------" << std::endl;
                std::string json_package;
                while(Decode(buffer_queue,&json_package))
                {
                    LogSpace::LOG(LogSpace::LogLevel::DEBUG) << client.Name() << "请求:" << json_package;
                    Request req;
                    bool ok = req.Deserialize(json_package);
                    if(!ok)
                    {
                        continue;
                    }

                    // 通过内部封装器，计算好结果。
                    Response resp = _func(req);

                    // 4.序列化
                    std::string json_str = resp.Serialize();

                    // 5.添加自定义长度。
                    std::string send_str = Encode(json_str);// 携带长度的应答报文了"len\r\n{result:XXX, code:XX}\r\n"

                    // 6.直接发送
                    sock->Send(send_str);
                }
            }
            else if(n == 0)
            {
                LogSpace::LOG(LogSpace::LogLevel::INFO) << "client" << client.Name() << "Quit";
                break;
            }
            else
            {
                LogSpace::LOG(LogSpace::LogLevel::INFO) << "client" << client.Name() << "Recv Error";
                break;
            }
        }
    }
    // 获取回应
    bool GetResponse(std::shared_ptr<Socket>& client,std::string& resp_buff,Response* resp)
    {
        // 面向字节流,你怎么保证，你的client读到的 一个网络字符串，就一定是一个完整的应答呢？？
        while(true)
        {
            int n = client->Recv(&resp_buff);
            if(n > 0)
            {
                std::string json_package;
                
                // 解码
                while( Decode(resp_buff,&json_package))
                {
                    resp->Deserialize(json_package);
                }

                return true;
            }
            else if(n == 0)
            {
                std::cout << "serve quit" << std::endl;
                return false;
            }
            else
            {
                std::cout << "recv error" << std::endl;
                return false;
            }
        }
    }
    std::string BuildRequestString(int x,int y,char oper)
    {
        Request req(x,y,oper);
        
        std::string json_req = req.Serialize();

        return Encode(json_req);
    }
private:
    func_t _func;
};
